//客户端代码
#include "client.h"
int sockfd;
pthread_mutex_t pmt;
struct bro bro_list[20];
char sig_in[60];
char RET[20];
MISC *misc;

int main(void) {
    char buf[512];
    misc = malloc(sizeof(MISC));
    // 客户端建立连接套接字
    misc->sockfd = socket(AF_INET, SOCK_STREAM, 0);
    misc->sig = 0; //表示没有信号
    if (sockfd < 0) {
        perror("socket");
        return -1;
    }

    // 2>声明服务器的IP和端口号
    misc->server.sin_family = AF_INET;
    misc->server.sin_port = htons(11123);
    misc->server.sin_addr.s_addr = inet_addr("192.168.3.18");

    // 3>连接服务器-点击应用的时候自动连接一次，成功或者失败都无所谓
    connect_To_Server();
    printf("Debug\n");
    // 建立一个线程，专门监听客户端 ctrl + c 退出程序的操作
    /*
      pthread_t client_ctrl_c;
      pthread_create(&client_ctrl_c, NULL, client_ctrlc, NULL);
    */
    // 线程一直存在，若是处于登录状态，该线程会强制关闭客户端和服务器端的进程，需要考虑修改客户端的fd
    char sig[50] = {0};  //用于接收账号数据 或 功能命令
    int ret;
    struct user my_info = {.fd = misc->sockfd}; // 结构体初始化
    INFO *info = malloc(sizeof(INFO)); //在栈中分配空间
    // my_info.fd = sockfd; // 退出登录时，账户会清零，回到初始界面，fd保持不变
    // qq_show();
    // qq_show1();
    // 创建一个线程，用于接收服务器发来的所有信号
    pthread_t tid;
    pthread_create(&tid, NULL, passive, &misc->sockfd); // 创建线程

init:
    // 或者只清除账号和密码部分
    init_page();         // 最开始的选择 登录注册退出 的界面
    printf("\033[16;68H");  //定位到输入光标处
    scanf("%s", sig);   //获取输入的字符串
    if (!strcmp(sig, "s")) { // 选择注册功能
sign:
        info->cmd = SIGNUP;
        sign_page();           // 显示注册界面
        printf("\033[16;62H"); // 光标定位到16，59
        memset(sig, 0, sizeof(sig));                       //
        scanf("%s", sig);
        if (!strcmp(sig, "e")) {
            goto exit_t;
        } else if (!strcmp(sig, "b")) {
            goto init;
        } else {
            sign_in(&my_info, sig);  //登录，并将个人信息传入
            while (1) { // 等待线程修改返回信号
                sleep(1);
                //如果没有延时函数，可能存在一种情况: 当线程执行完弹窗后，主程序一直在执行while循环，占据了系统资源，而线程又来不及修改RET的值，故主程序一直无法退出while循环，弹窗一直存在
                if (!strcmp(RET, "signerror")) {
                    bzero(RET, sizeof(RET));
                    //因为无法确定，对RET的判断和赋值谁先开始，所以每次使用完信号值后，也需要对其进行清零，防止存留值对下次判断造成干扰
                    //这种方式还是很愚蠢，无法保证bzero 和 strcpy对RET的操作是原子的。
                    goto sign; // 注册失败
                } else if (!strcmp(RET, "signok")) {
                    bzero(RET, sizeof(RET));
                    goto init; // 注册成功，执行下一次循环，回到Init_page界面
                }
            }
        }
    } else if (!strcmp(sig, "e")) { // 选择退出功能
exit_t:
        pop_up("程序退出中", 3);
        printf(LIGHT_BLUE);
        int i;
        int j = 2;
        while (j) {
            fflush(0);
            printf("\033[18;76H");
            for (i = 0; i < 4; i++) {
                printf(".");
                fflush(stdout);
                usleep(500000);
            }
            clear_up(18, 76, 4); // 行18，列77，清空4个单位
            j--;
        }
        printf(NONE);
        system("clear");
        printf("\n");
        system("clear");
        sig_send(misc->sockfd, "exit"); // 给服务器发送退出信号，杀死服务器端给客户端开的进程
        exit(-1); // 杀死客户端程序
    } else {    // 选择登录程序
        bzero(info, sizeof(INFO));
        info->fd = misc->sockfd;  //保存认证的句柄
        info->cmd = LOGIN;
        //根据输入确定是否要保存信息
        //bzero(info->uid, sizeof(info->uid));
        strcpy(info->uid, sig);
        //如果输入非上述字符s e，则按下回车键应该允许用户开始输入密码
        printf("\033[20;68H");  //定位到输入密码栏
        scanf("%s", info->passwd);
        //bzero(info->passwd, sizeof(info->passwd));
        //strcpy(info->passwd, my_info.passwd);

        //按下回车键后，显示正在连接的画面
        pop_up("程序登录中", 0);
        int i;
        int j = 2;
        while (j) {
            fflush(0);
            printf("\033[18;76H");
            for (i = 0; i < 4; i++) {
                printf(".");
                fflush(stdout);
                usleep(500000);
            }
            clear_up(18, 76, 4); // 行18，列77，清空4个单位
            j--;
        }

        bzero(buf, sizeof(buf)); // 结构体json打包
        info_To_Json(info, buf);
        printf("client buf = %s\n", buf);
        send(info->fd, buf, strlen(buf), 0); //发送过去后，若是服务器有响应，则在线程中修改该变量，没有响应就会直接中断进程
    }
    while (1) {

    }
next:
    /*--------------功能模块--------------*/
    while (1) {
        // 刷新主页面
        re_fresh(sockfd, bro_list);
        //定位光标，等待输入命令
        printf("\033[30;66H");
        //bzero(sign_in, sizeof(sign_in));
        scanf("%s", sig_in);
        switch (atoi(sig_in)) {
            case 1 ... 20: // 向代号1到20的好友直接聊天
            //线程上锁
            talk_to(&my_info, bro_list[atoi(sig_in) - 1].uid);
            //线程解锁
            break;
        }
        if (!strcmp(sig_in, "Q")) {
            sig_send(my_info.fd, "logout");                 // 发送logout信号
            bzero(&my_info.uid, sizeof(my_info.uid));       // 清空账号
            bzero(&my_info.passwd, sizeof(my_info.passwd)); // 清空密码
            pop_up("退出登录成功!!", 2);
            goto init;                                      // 回到初始界面
        } else if (!strcmp(sig_in, "A")) {
            add_bro(&my_info);
            while (1) {
                sleep(1);  //等待修改信号
                if (!strcmp(RET, "adderror")) {
                    bzero(RET, sizeof(RET));
                    break;
                } else if (!strcmp(RET, "adderror1")) {
                    //同时需要清空判断标志
                    bzero(RET, sizeof(RET));
                    break; // 登录失败退出循环，回到init_page()界面
                } else if (!strcmp(RET, "addok")){
                    bzero(RET, sizeof(RET));
                    break;
                } else if (!strcmp(RET, "adderror2")){
                    bzero(RET, sizeof(RET));
                    break;
                }
            }
        } else if (!strcmp(sig_in, "R")) {
            //continue;
            re_fresh(my_info.fd, bro_list);
        } else if (!strcmp(sig_in, "D")) {
            del_bro(&my_info);
            while (1) {
                sleep(1);  //等待修改信号
                if (!strcmp(RET, "delerror")) {
                    bzero(RET, sizeof(RET));
                    break;
                } else if (!strcmp(RET, "delok")) {
                    //同时需要清空判断标志
                    bzero(RET, sizeof(RET));
                    break; // 登录失败退出循环，回到init_page()界面
                }
            }
        }
    }

    return 0;
}
